//+------------------------------------------------------------------+
//|                                                      Strategy.mq5|
//|                        Copyright 2023, MetaQuotes Software Corp.|
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <Trade\Trade.mqh>
CTrade trade;

//--- 指标参数
input int    FastMA_Period = 15;     // 快速MA周期
input int    SlowMA_Period = 30;    // 慢速MA周期
input int    MACD_Fast = 6;        // MACD快线
input int    MACD_Slow = 13;        // MACD慢线
input int    MACD_Signal = 5;       // MACD信号线

int      maHandleK;       // MA 指标句柄
double   maValuesK[10];   // 存储最近 10 根 K 线的 MA 值

double Macd0 = 0.008;
datetime LastOrderTime = 0;


//--- 交易参数
input double LotSize = 0.01;         // 交易手数
input int    StopLoss = 20000;        // 止损点数
input int    TakeProfit = 200;      // 止盈点数

//--- 指标句柄
int fastMA_handle, slowMA_handle, macd_handle;
double fastMA[], slowMA[], macdMain[];

int atrHandle;

int maHandle;
double maValues[];

bool triggered = false; // 防止重复触发标志

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   EventSetTimer(1);
   maHandle = iMA(_Symbol, _Period, 10, 0, MODE_EMA, PRICE_CLOSE);
   maHandleK = iMA(_Symbol, _Period, 15, 0, MODE_SMA, PRICE_CLOSE);
   ArraySetAsSeries(maValues, true);
//--- 初始化指标句柄
   fastMA_handle = iMA(_Symbol, _Period, FastMA_Period, 0, MODE_SMA, PRICE_CLOSE);
   slowMA_handle = iMA(_Symbol, _Period, SlowMA_Period, 0, MODE_SMA, PRICE_CLOSE);
   macd_handle = iMACD(_Symbol, _Period, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE);
   atrHandle = iATR(_Symbol, _Period, 14);

//--- 设置数组为时间序列
   ArraySetAsSeries(fastMA, true);
   ArraySetAsSeries(slowMA, true);
   ArraySetAsSeries(macdMain, true);

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer(); // 删除定时器
  }

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
   datetime currentTime = TimeCurrent();                // 获取当前服务器时间
   datetime nextBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);   // 计算下一根K线开始时间
   int remainingSeconds = (int)(nextBarTime - currentTime); // 计算剩余秒数
//Print(remainingSeconds,"====计算剩余秒数=",nextBarTime);
// 当剩余5秒且未触发过时执行
   if(remainingSeconds == -5 && !triggered)
     {
      // Print(remainingSeconds,"====计算剩余秒数=",nextBarTime);
      triggered = true; // 设置触发标志
      // Alert("5 seconds before new bar! Current Time: ", TimeToString(currentTime));
      // 此处可添加交易操作，例如：
      datetime currentBarTime = iTime(_Symbol, _Period, 0);
      if(LastOrderTime != currentBarTime)
        {
         LastOrderTime = currentBarTime; // 更新最后开单时间
         OnTicks();
        }

     }

// 当剩余时间超过5秒时重置触发标志
   if(remainingSeconds > -5)
     {
      triggered = false;
     }
  }
//+------------------------------------------------------------------+
//| 计算线性回归斜率函数                                            |
//+------------------------------------------------------------------+
double CalculateRegressionSlope(double &data[], int length)
  {
   double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
   for(int i = 0; i < length; i++)
     {
      sumX += i;          // X 轴为时间序列（0,1,2,...,length-1）
      sumY += data[i];
      sumXY += i * data[i];
      sumX2 += i * i;
     }
   double slope = (length * sumXY - sumX * sumY) / (length * sumX2 - sumX * sumX);
   return slope;
  }
//+------------------------------------------------------------------+
//| 获取指定天数前的MA趋势（返回1=上涨，-1=下跌，0=无趋势）             |
//+------------------------------------------------------------------+
int GetMATrendDaysAgo(int days)
  {
// 计算需要回溯的K线数量
   int requiredBars = Bars(_Symbol, _Period) - 1;
   int targetIndex = -1;

// 查找5天前的K线索引
   datetime targetTime = TimeCurrent() - days*86400;
   for(int i=0; i<requiredBars; i++)
     {
      if(TimeCurrent() - i*PeriodSeconds() >= targetTime)
        {
         targetIndex = i;
         break;
        }
     }

// 获取足够长度的MA数据
   if(CopyBuffer(maHandle, 0, 0, targetIndex+2, maValues) < targetIndex+2)
     {
      Print("获取MA数据失败");
      return 0;
     }

// 趋势判断逻辑
   if(maValues[targetIndex] > maValues[targetIndex+1])
      return 1;  // 上涨
   if(maValues[targetIndex] < maValues[targetIndex+1])
      return -1; // 下跌
   return 0; // 平缓
  }


//获取历史订单的最长持仓时间
int FindLongestHoldingOrder()
  {
   ulong longestTicket = 0;
   long longestDuration = 0;

// 检查当前持仓
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0)
         continue;

      datetime openTime = (datetime)PositionGetInteger(POSITION_TIME);
      long duration = TimeCurrent() - openTime;

      if(duration > longestDuration)
        {
         longestDuration = duration;
         longestTicket = ticket;
        }
     }

// 检查历史订单
   HistorySelect(0, TimeCurrent());
   for(int i = HistoryOrdersTotal() - 1; i >= 0; i--)
     {
      ulong ticket = HistoryOrderGetTicket(i);
      if(ticket == 0)
         continue;

      ENUM_ORDER_TYPE type = (ENUM_ORDER_TYPE)HistoryOrderGetInteger(ticket, ORDER_TYPE);
      if(type != ORDER_TYPE_BUY && type != ORDER_TYPE_SELL)
         continue;

      datetime openTime = (datetime)HistoryOrderGetInteger(ticket, ORDER_TIME_SETUP);
      datetime closeTime = (datetime)HistoryOrderGetInteger(ticket, ORDER_TIME_DONE);
      long duration = closeTime - openTime;

      if(duration > longestDuration)
        {
         longestDuration = duration;
         longestTicket = ticket;
        }
     }

// 输出结果
   if(longestTicket != 0)
     {

      Print("longestDuration",longestDuration);
      int days = (int)(longestDuration / 86400);
      int hours = (int)((longestDuration % 86400) / 3600);
      int minutes = (int)((longestDuration % 3600) / 60);
      Print("最长持仓订单 Ticket=", longestTicket,
            "，时长=", days, "天 ", hours, "小时 ", minutes, "分钟");
      if(minutes>50)
        {
         return longestTicket;
        }
      return 0;
     }
   else
     {
      return 0;
     }
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
// 遍历所有持仓订单，获取开盘价和当前价
void GetPositionPrices()
  {
// 遍历所有持仓
   ulong ticketVal = FindLongestHoldingOrder();
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      // 获取持仓订单的Ticket
      ulong ticket = PositionGetTicket(i);
      if(ticketVal==ticket)
        {
         if(ticket == 0)
            continue;

         // 获取订单属性
         string symbol = PositionGetString(POSITION_SYMBOL);       // 交易品种
         double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); // 开盘价
         double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT); // 当前价
         ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // 持仓类型
         //double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
         // Print("longestDuration",longestDuration);
         if(openPrice - 0.60 <=  currentPrice)
           {
            trade.PositionClose(ticket);
           }
         // 输出结果
         PrintFormat("订单 Ticket: %d, 品种: %s, 类型: %s\n"
                     "开盘价 = %.5f, 当前价 = %.5f",
                     ticket, symbol, EnumToString(type), openPrice, currentPrice);
        }
     }
  }
//+------------------------------------------------------------------+
//| 平所有仓位                                                       |
//+------------------------------------------------------------------+
void CloseAllPositions()
  {
   for(int i = PositionsTotal()-1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      if(PositionGetString(POSITION_SYMBOL) == _Symbol)
        {
         double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
         double currentSL = PositionGetDouble(POSITION_SL);
         double currentTP = PositionGetDouble(POSITION_TP);
         double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
         double requiredPrice = openPrice;
         if(currentPrice - openPrice <0)
           {
            double newSl=NormalizeDouble(currentPrice - 1 *_Point,_Digits);
            trade.PositionModify(_Symbol,newSl,0);
           }
        }
     }
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTicks()
  {

   int trend5DaysAgo = GetMATrendDaysAgo(0.25);
// int trend5DaysAgo2 = GetMATrendDaysAgo(0.075);

   switch(trend5DaysAgo)
     {
      case 1:
         // Print("5天前MA趋势：上涨",trend5DaysAgo);
         break;
      case -1:
         // Print("5天前MA趋势：下跌",trend5DaysAgo);
         CloseAllPositions();
         break;
      default:
         Print("0.1天前MA趋势：不明");
     }

// GetPositionPrices();

// 复制 10 根已关闭的 K 线（索引 1 到 10）
   if(CopyBuffer(maHandleK, 0, 1, 10, maValuesK) < 6)
     {
      Print("复制数据失败，错误代码：", GetLastError());
      return;
     }


// 计算线性回归斜率
   double regressionSlope = CalculateRegressionSlope(maValuesK, 10);
   Print("KK斜率：",regressionSlope);
   if(regressionSlope<0.001)
     {
      CloseAllPositions();
      return;
     }



   Print("计算10K线性回归斜率：", regressionSlope);

//--- 获取指标数据
   if(CopyBuffer(fastMA_handle, 0, 0, 3, fastMA) < 3)
      return;
   if(CopyBuffer(slowMA_handle, 0, 0, 3, slowMA) < 3)
      return;
   if(CopyBuffer(macd_handle, 0, 0, 3, macdMain) < 3)
      return;



//--- 获取当前价格
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

//--- 计算交易信号
   bool maBullish = fastMA[0] > slowMA[0] && fastMA[1] <= slowMA[1];
   bool maBearish = fastMA[0] < slowMA[0] && fastMA[1] >= slowMA[1];
   bool macdBullish = macdMain[0] >= Macd0 && macdMain[1] <= 0;
   bool macdBearish = macdMain[0] < 0 && macdMain[1] >= 0;

//--- 检查持仓
   bool hasLong = PositionSelect(_Symbol) && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY;
   bool hasShort = PositionSelect(_Symbol) && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL;

   if(regressionSlope > 0 && !hasLong)
     {
      double sl = ask - StopLoss * _Point;
      double tp = ask + TakeProfit * _Point;
      trade.Buy(LotSize, _Symbol, ask, sl, tp, "多头入场");
     }

   if(maBearish && macdBearish)
     {
      CloseAllPositions();
     }
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
